package com.ruoyi.home.utils;

import com.ruoyi.home.domain.BusinessCostTypesEnum;
import com.ruoyi.home.domain.CalculateFkPlanForm;
import com.ruoyi.home.domain.CwPaymentPlanDto;



import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 收房合同录入：根据合同租约信息生成付款计划信息
 * 
 * @author ASUS
 *
 */
public class PayMentPlanGenerator {

	public static void main(String[] args) throws ParseException {
		CalculateFkPlanForm form = new CalculateFkPlanForm();
		// 合同开始日
		form.setLeaseStartTime(new SimpleDateFormat(DateUtils.DATE_PATTERN).parse("2018-04-21"));
		// 合同结束日
		form.setLeaseEndTime(new SimpleDateFormat(DateUtils.DATE_PATTERN).parse("2018-04-21"));
		// 月租金
		form.setMonthRent(new BigDecimal(2700));
		// 押金
		form.setDepositMoney(new BigDecimal(2700));
		// 押几
		form.setDepositType(2);
		// 付几
		form.setPaymentType(2);
		// 生成付款计划
		generatePayMentPlan(form);
	}

	/**
	 * 根据租约信息生成押金、出房付款计划
	 * 
	 * @param form
	 *            租约信息
	 * @return 付款计划信息
	 * @throws ParseException
	 */
	public static List<CwPaymentPlanDto> generatePayMentPlan(CalculateFkPlanForm form) {

		SimpleDateFormat sdf = new SimpleDateFormat(DateUtils.DATE_PATTERN);
		System.out.println("合同租期:" + sdf.format(form.getLeaseStartTime()) + " ~~ " + sdf.format(form.getLeaseEndTime()));
		// 付款周期 付几
		int cycle = form.getPaymentType();
		// 最小周期（一个月）
		int minCycle = 1;
		// 各账期计划
		List<CwPaymentPlanDto> planList = new ArrayList<CwPaymentPlanDto>();
		// 总押金 = 押金 * 押几
		BigDecimal totalDeposit = form.getDepositMoney().multiply(new BigDecimal(form.getDepositType()));
		// 月租金
		BigDecimal monthRent = form.getMonthRent();
		// 足账期的金额 = 月租金 * 付几
		BigDecimal oneCycleRent = monthRent.multiply(new BigDecimal(cycle));
		// 当前账期租金(实际)
		BigDecimal currentCycleMoney = BigDecimal.ZERO;
		// 总钱数
		BigDecimal totalMoney = BigDecimal.ZERO;
		// 一天的租金 = 月租/30
		BigDecimal oneDayMoney =BigDecimal.valueOf(MyJinRongUtils.div(monthRent.doubleValue(), 30l, 2));
		// 合同开始日
		Date contractStartDate = form.getLeaseStartTime();
		// 合同截止日
		Date contractEndDate = form.getLeaseEndTime();
		// 账期开始日
		Date planStartDate = null;
		// 账期数
		int planNum = 1;
		List<CwPaymentPlanDto> payMentltems = form.getPayMentltems();
		// 首期房租之后的账期是否要重新生成
		boolean generatePlanAfterPreCycle = false;
		if (null != form.getPreCycleChange() && 1 == form.getPreCycleChange()) {
			generatePlanAfterPreCycle = true;
			planNum = 2;
			// 账期开始日 = 首期结束日 + 1
			planStartDate = DateUtils.getDateAfterDays(payMentltems.get(0).getPaymentDaysEnd(), 1);
		} else {
			// 账期开始日 = 合同起始日
			planStartDate = contractStartDate;
		}
		// 账期结束日 当前账期的结束日期是【下一账期起始日 - 1】
		Date planEndDate = DateUtils.getDateAfterDays(DateUtils.getDateAfterMonths(planStartDate, cycle), -1);// 第一个账期预计结束日

		if (contractEndDate.before(planEndDate)) {// 合同租约不足一个付款周期的账期时的押金和房租付款计划的生成
			Date currentCycleStartDate = planStartDate;
			// 当前账期租金 = 足月数 * 月租金 + 不足月天数 *月租金/30
			planEndDate = DateUtils.getDateAfterDays(DateUtils.getDateAfterMonths(planStartDate, minCycle), -1);
			if (contractEndDate.before(planEndDate)) {// 不足一个付款周期的账期时 AND 不足一个月时
				// 当前账期结束日 = 合同结束日
				planEndDate = contractEndDate;
				// 当前账期租金 = 不足月天数 *月租金/30
				double diffDay = DateUtils.getDiffDay(contractStartDate, contractEndDate);
				double mul = MyJinRongUtils.mul(oneDayMoney.doubleValue(), diffDay);
				currentCycleMoney = BigDecimal.valueOf(mul);
			} else {// 不足一个付款周期的账期时 AND 超过一个月时
				// 累加 第一个足月金额
				currentCycleMoney.add(monthRent);
				// 合同结束日期在当前账期结束日期之后
				while (contractEndDate.after(planEndDate)) {
					// 下一个足月数起始日 AND 预计结束日
					planStartDate = DateUtils.getDateAfterMonths(planStartDate, minCycle);
					planEndDate = DateUtils.getDateAfterDays(DateUtils.getDateAfterMonths(planStartDate, minCycle), -1);// 预计结束日
					// 合同结束日在该账期之后，继续写一个
					if (contractEndDate.before(planEndDate)) {
						planEndDate = contractEndDate;// 实际结束日
						// 累加 不足月天数 *月租金/30
						currentCycleMoney = currentCycleMoney.add(oneDayMoney
								.multiply(new BigDecimal(DateUtils.getDiffDay(planStartDate, contractEndDate))));
					} else {
						// 累加 足月金额
						currentCycleMoney = currentCycleMoney.add(monthRent);
					}
				}
			}
			if (generatePlanAfterPreCycle == false) {
				// 押金不为0时，才生成押金的付款计划
				if (isNotZero(totalDeposit)) {
					// 添加押金 计划DTO
					totalMoney = totalMoney.add(totalDeposit);
					addPlan(planList, planNum, BusinessCostTypesEnum.YAJIN.getIndex(), totalDeposit, planStartDate,
							planStartDate, planEndDate);
				}
				// 添加首期金额 计划DTO
				if (isNotZero(currentCycleMoney)) {
					totalMoney = totalMoney.add(currentCycleMoney);
					addPlan(planList, planNum, BusinessCostTypesEnum.ZUJIN.getIndex(), currentCycleMoney,
							currentCycleStartDate, currentCycleStartDate, contractEndDate);
				}
			} else {
				// 添加第二个账期金额 计划DTO
				if (isNotZero(currentCycleMoney)) {
					totalMoney = totalMoney.add(currentCycleMoney);
					addPlan(planList, planNum, BusinessCostTypesEnum.ZUJIN.getIndex(), currentCycleMoney,
							getPayableDate(currentCycleStartDate), currentCycleStartDate, contractEndDate);
				}
			}
		} else {// 合同租约超过一个付款周期的账期时的押金和房租付款计划的生成
			// 累加 第一个足账期的金额
			currentCycleMoney = currentCycleMoney.add(oneCycleRent);
			if (generatePlanAfterPreCycle == false) {
				// 押金不为0时，才生成押金的付款计划
				if (isNotZero(totalDeposit)) {
					// 添加押金 计划DTO
					totalMoney = totalMoney.add(totalDeposit);
					addPlan(planList, planNum, BusinessCostTypesEnum.YAJIN.getIndex(), totalDeposit, planStartDate,
							planStartDate, planEndDate);
				}
				// 添加首期金额 计划DTO
				totalMoney = totalMoney.add(currentCycleMoney);
				addPlan(planList, planNum, BusinessCostTypesEnum.ZUJIN.getIndex(), currentCycleMoney, planStartDate,
						planStartDate, planEndDate);
			} else {
				// 添加第二个账期金额 计划DTO
				totalMoney = totalMoney.add(currentCycleMoney);
				addPlan(planList, planNum, BusinessCostTypesEnum.ZUJIN.getIndex(), currentCycleMoney,
						getPayableDate(planStartDate), planStartDate, planEndDate);
			}
			while (contractEndDate.after(planEndDate)) {
				planNum++;
				// 下一个账期的起始日为【前一账期的开始日加(付款周期)个月】
				planStartDate = DateUtils.getDateAfterMonths(planStartDate, cycle);
				planEndDate = DateUtils.getDateAfterDays(DateUtils.getDateAfterMonths(planStartDate, cycle), -1);
				// 【下一个付款周期的账期起始日到合同结束日】不足一个付款周期的账期时的房租付款计划的生成
				if (contractEndDate.before(planEndDate)) {
					Date currentCycleStartDate = planStartDate;
					// 调用不足一账期的计算处理
					currentCycleMoney = BigDecimal.ZERO;
					// 当前账期租金 = 足月数 * 月租金 + 不足月天数 *月租金/30
					planEndDate = DateUtils.getDateAfterDays(DateUtils.getDateAfterMonths(planStartDate, minCycle), -1);
					if (contractEndDate.before(planEndDate)) {// 不足一个付款周期的账期时 AND 不足一个月时
						// 当前账期租金 = 不足月天数 *月租金/30
						currentCycleMoney = oneDayMoney
								.multiply(new BigDecimal(DateUtils.getDiffDay(planStartDate, contractEndDate)));
					} else {// 不足一个付款周期的账期时 AND 超过一个月时
						// 累加 第一个足月金额
						currentCycleMoney.add(monthRent);
						// 合同结束日期在当前账期结束日期之后
						while (contractEndDate.after(planEndDate)) {
							// 下一个足月数起始日 AND 预计结束日
							planStartDate = DateUtils.getDateAfterMonths(planStartDate, minCycle);
							planEndDate = DateUtils
									.getDateAfterDays(DateUtils.getDateAfterMonths(planStartDate, minCycle), -1);// 预计结束日
							// 合同结束日在该账期之后，继续写一个
							if (contractEndDate.before(planEndDate)) {
								// 累加 不足月天数 *月租金/30
								currentCycleMoney = currentCycleMoney.add(oneDayMoney.multiply(
										new BigDecimal(DateUtils.getDiffDay(planStartDate, contractEndDate))));
							} else {
								// 累加 足月金额
								currentCycleMoney = currentCycleMoney.add(monthRent);
							}
						}
					}
					// 添加不足一个账期的付款计划信息
					if (isNotZero(currentCycleMoney)) {
						// 生成该账期的付款计划
						totalMoney = totalMoney.add(currentCycleMoney);// 累加最后一个不足一个账期的金额
						addPlan(planList, planNum, BusinessCostTypesEnum.ZUJIN.getIndex(), currentCycleMoney,
								getPayableDate(currentCycleStartDate), currentCycleStartDate, contractEndDate);
					}
				} else {
					currentCycleMoney = oneCycleRent;
					// 生成该账期的付款计划
					totalMoney = totalMoney.add(currentCycleMoney);
					addPlan(planList, planNum, BusinessCostTypesEnum.ZUJIN.getIndex(), currentCycleMoney,
							getPayableDate(planStartDate), planStartDate, planEndDate);
				}
			}
		}

		List<CwPaymentPlanDto> finalPlanList = new ArrayList<CwPaymentPlanDto>();
		if (generatePlanAfterPreCycle == true) {
			// 首期之后的账期总金额
			BigDecimal totalAmountAfterFirstCycle = totalMoney;
			// 无押金时，firstItemInfo为首期房租；有押金时，firstItemInfo为押金
			CwPaymentPlanDto firstItemInfo = payMentltems.get(0);
			finalPlanList.add(firstItemInfo);
			// 有押金时
			if (isNotZero(totalDeposit)) {
				// 添加首期房租
				CwPaymentPlanDto firstCycleRentInfo = null;
				if (payMentltems.size() > 1) {
					firstCycleRentInfo = payMentltems.get(1);
					// 合同周期同押金一致
					firstCycleRentInfo.setPaymentDaysBegin(firstItemInfo.getPaymentDaysBegin());
					firstCycleRentInfo.setPaymentDaysEnd(firstItemInfo.getPaymentDaysEnd());
					// 首期房租 = 租期总金额 - 押金 - 首期之后的账期总金额
					firstCycleRentInfo.setPaymentAmount(form.getTotalAmount().subtract(firstItemInfo.getPaymentAmount())
							.subtract(totalAmountAfterFirstCycle));
					// 添加首期房租
					finalPlanList.add(firstCycleRentInfo);
				}
			} else {
				// 首期房租 = 租期总金额 - 押金 - 首期之后的账期总金额
				firstItemInfo.setPaymentAmount(form.getTotalAmount().subtract(totalAmountAfterFirstCycle));
			}
			// 添加首期之后的付款计划
			for (CwPaymentPlanDto cwPayMentPlanDto : planList) {
				finalPlanList.add(cwPayMentPlanDto);
			}
		} else {
			finalPlanList = planList;
		}

		for (CwPaymentPlanDto cwReceiptPlanDto : finalPlanList) {
			System.out.println(
					"第" + cwReceiptPlanDto.getPayNumber() + "期：" + "   应付金额：" + cwReceiptPlanDto.getPaymentAmount()
							+ "   付款期间：" + sdf.format(cwReceiptPlanDto.getPaymentDaysBegin()) + "至"
							+ sdf.format(cwReceiptPlanDto.getPaymentDaysEnd()));
		}

		return finalPlanList;
	}

	/**
	 * 计算应付日期
	 * 
	 * @param planStartDate
	 *            账期开始日
	 * @param advanceDays
	 *            提前天数
	 * @param fixedDayInMonth
	 *            固定日期号 1~28之间的日期
	 * @return
	 */
	private static Date getPayableDate(Date planStartDate) {
		Date payableDate = null;
		payableDate = planStartDate;
		return payableDate;
	}

	/**
	 * 编辑添加各个账期信息
	 * 
	 * @param planList
	 * @param payNumber
	 *            账期
	 * @param itemType
	 *            款项（参照CostTypesEnum.java的定义）
	 * @param paymentAmount
	 *            账期金额
	 * @param payableDate
	 *            应付日期
	 * @param paymentDaysBegin
	 *            账期开始日期
	 * @param paymentDaysEnd
	 *            账期结束日期
	 */
	private static void addPlan(List<CwPaymentPlanDto> planList, int payNumber, int itemType, BigDecimal paymentAmount,
			Date payableDate, Date paymentDaysBegin, Date paymentDaysEnd) {
		CwPaymentPlanDto payMentPlan = new CwPaymentPlanDto();
		// 账期
		payMentPlan.setPayNumber(payNumber);
		// 款项
		payMentPlan.setItemType(itemType);
		// 应付金额
		payMentPlan.setPaymentAmount(paymentAmount);
		// 账期开始日
		payMentPlan.setPaymentDaysBegin(paymentDaysBegin);
		// 账期结束日
		payMentPlan.setPaymentDaysEnd(paymentDaysEnd);
		// 税费
		payMentPlan.setTax(BigDecimal.ZERO);
		// 应付日期
		payMentPlan.setPayableDate(payableDate);
		planList.add(payMentPlan);
	}

	private static boolean isNotZero(BigDecimal amount) {
		if (BigDecimal.ZERO.compareTo(amount) != 0) {
			return true;
		} else {
			return false;
		}
	}
}
